from sqlalchemy import insert,select,update,delete,func,join,engine
from sqlalchemy.sql import text,func,or_,and_
from sqlalchemy.engine import Connection, CursorResult, LegacyRow,Transaction
from eim.DataBasModals.mode import t_dbtables,t_tablecolumns,t_rs_dstbl,t_joinconditions,t_qycolumns,t_qycondition
from eim.tools.dbtool import DBTool
from eim import db,tokenScheme,secret_key
from eim import tokenScheme
import jwt,time

class ReportService:
    """
    报表服务
    """
    def __init__(self,dbcon):
        """
        初始化报表数据库服务

        Args:
            dbcon (_type_): 数据库连接
        """
        self.db = dbcon
        
    # 新增数据库表记录    
    def insertNewTable(self,tblcode:str,ename:str,cname:str,comment:str)->int:
        """
        添加新的数据表记录

        Args:
            tblcode (str): 数据表编号
            tblname (str): 数据表名
            ename (str): 英文名
            cname (str): 中文名称
            comment (str): 注释

        Returns:
            int: 新增表记录的ID
        """
        try:
            con = db.engine.connect()
            pms={
                "tblcode":tblcode,
                "ename": ename,
                "cname": cname,
                "comment": comment
            }
            qry=insert(t_dbtables).values(pms)
            res:CursorResult = con.execute(qry)
            return res.inserted_primary_key[0]
        except Exception as es:
            raise es

    # 更新数据表记录条目
    def upgradeTableByid(self,id:int,pms:dict)->int:
        """
        根据ID更新数据表记录

        Args:
            id (int): id
            pms (dict): 更新的内容

        Returns:
            int: 受影响的行数
        """
        try:
            if("tblcode" in pms.keys()):
                raise Exception("表格条目编码不允许修改")
            con:Connection = db.engine.connect()
            qry = update(t_dbtables).values(pms)
            res:CursorResult = con.execute(qry)
            return res.rowcount
        except Exception as es:
            raise es
    
    # 删除数据表记录
    def deleteTableRecord(self,id:int):
        """
        删除指定id的数据表记录

        Args:
            id (int): 数据表记录id
        """
        try:
            con:Connection = db.engine.connect()
            # 首先获取数据表编码
            qry = select(t_dbtables.c.tblcode).where(t_dbtables.c.ID==id)
            res:LegacyRow = con.execute(qry).first()
            tblcode = res['tblcode']
            
            # 判定列清单中是否存在上述数据表编码
            qry = select(func.count()).where(t_tablecolumns.c.tblcode==tblcode)
            res:CursorResult = con.execute(qry)
            cnt = res.scalar()
            if(cnt>0):
                raise Exception("存在使用该表的字段记录，当前不能删除!")
            else:
                qry = select(func.count()).where(t_rs_dstbl.c.tblcode==tblcode)
                res:CursorResult = con.execute(qry)
                cnt = res.scalar()
                if(cnt>0):
                    raise Exception("一些数据源正在使用该表记录，当前不能删除!")
            
            # 该数据表记录没有被使用时可以删除
            qry = delete(t_dbtables)
            qry = qry.where(text(f"ID='{id}'"))
            con.execute(qry)
        except Exception as es:
            raise es
    
    # 分页获取数据表记录
    def pageListTableRecord(self,pn:int,ps:int)->list:
        """
        分页获取数据表记录

        Args:
            pn (int): 分页页码
            ps (int): 页面尺寸

        Returns:
            list: 记录列表
        """
        try:
            if((not isinstance(pn,int)) or (not isinstance(ps,int))):
                raise Exception("分页页码和页面尺寸必须为整型数据")
            if(pn<1):
                pn=1
            if(ps<1):
                ps=30
            offset=(pn-1)*ps
            con:Connection = db.engine.connect()
            qry= select(t_dbtables).limit(ps).offset(offset)
            result = []
            res:CursorResult = con.execute(qry)
            for row in res.fetchall():
                result.append(row._asdict())
            return result
        except Exception as es:
            raise es
    
    # 获取数据表记录总量
    def getDBTableCount(self)->int:
        """
        获取数据表记录的总数量

        Returns:
            int: 返回数据表记录的总数量
        """
        try:
            con:Connection = db.engine.connect()
            qry = select(func.count(t_dbtables.c.ID))
            res:CursorResult = con.execute(qry)
            return res.scalar()
        except Exception as es:
            raise es
    
    def getDBTaleCode(self,tblname:str)->str:
        """
        通过表名称获取表编码

        Args:
            tbname (str): 表名称编码
        Returns:
            str: 表编码
        """
        try:
            con:Connection = db.engine.connect()
            qry=select(t_dbtables.c.tblcode)
            qry=qry.where(t_dbtables.c.ename==tblname).limit(1).offset(0)
            res:CursorResult = con.execute(qry)
            return res.scalar()
        except Exception as es:
            raise es
        
    # 通过数据表编码获取数据表id
    def getDBTableRecByCode(self,tblcode:str)->int:
        """
        通过数据表记录编号获取数据表id

        Args:
            tblcode (str): 数据表编号

        Returns:
            int: 返回数据表记录ID如果数据表记录
        """
        try:
            con = db.engine.connect()
            qry = select(t_dbtables.c.ID)
            qry = qry.where(text(f"tblcode='{tblcode}'"))
            res:CursorResult = con.execute(qry)
            return res.scalar()
        except Exception as es:
            return es
    
    # 添加新的数据表字段   
    def insertNewField(self,fcode:str,tblcode:str,ename:str,cname:str,ftype:str,flength:int,comment:str)->int:
        """
        添加新的数据表字段

        Args:
            fcode (str): 数据字段编码
            tblcode (str): 数据表编码
            ename (str): 英文名称
            cname (str): 中文名称
            ftype (str): 数据字段类型
            flength (int): 数据字段长度
            comment (str): 数据字段说明

        Returns:
            int: 返回新增数据字段id
        """
        try:
            if(ename==''):
                raise Exception("字段的英文名称不能为空")
            if(fcode==''):
                raise Exception("字段编码不能为空")
            tblid = self.getDBTableRecByCode(tblcode)
            if(tblid is None):
                raise Exception("指定数据表编号的记录不存在")
            
            pms={
                "fcode": fcode,
                "tblcode": tblcode,
                "ename": ename,
                "cname": cname,
                "ftype": ftype,
                "flength": flength,
                "comment": comment
            }
            con = db.engine.connect()
            qry = insert(t_tablecolumns).values(pms)
            res:CursorResult = con.execute(qry)
            return res.inserted_primary_key[0]
        except Exception as es:
            raise es
    
    # 根据表格编号获取字段列表
    def getColsByTblcode(self,tblcode)->list:
        """
        根据表格编号获取字段列表

        Args:
            tblcode (_type_): 表格编码

        Returns:
            list: 获取字段列表
        """
        try:
            cols=[]
            qry=select(t_tablecolumns).where(t_tablecolumns.c.tblcode==tblcode)
            con = db.engine.connect()
            for row in con.execute(qry).fetchall():
                cols.append(row._asdict())
            return cols
        except Exception as es:
            raise es
    
    # 更新指定id的数据表字段信息
    def upgradeTblCol(self,id:str,pms:dict)->int:
        """
        更新指定id的数据表字段信息

        Args:
            id (str): 待更新的数据表字段
            pms (dict): 待更新的信息

        Returns:
            int: 返回受影响行数
        """
        try:
            if('fcode' in pms.keys()):
                raise Exception("字段编码不能被修改")
            if('tblcode' in pms.keys()):
                raise Exception("数据表编码不能被修改")
            con = db.engine.connect()
            qry= update(t_tablecolumns).values(pms)
            qry=qry.where(t_tablecolumns.c.ID==id)
            res:CursorResult = con.execute(qry)
            return res.rowcount
        except Exception as es:
            raise es
    
    # 删除指定id的数据表列
    def deleteTblCol(self,id:int):
        """
        删除指定ID的数据表列

        Args:
            id (int): 待删除的数据表列
        """
        try:
            con = db.engine.connect()
            qry = select(t_tablecolumns.c.fcode).where(t_tablecolumns.c.ID==id)
            res:CursorResult = con.execute(qry)
            fcode = res.scalar()
            
            # 判断连接条件表是否使用该数据表字段
            qry=select(t_joinconditions.c.ID)
            qry=qry.where(or_(t_joinconditions.c.lcolcode==fcode))
            qry=qry.where(or_(t_joinconditions.c.rcolcode==fcode))
            res:CursorResult= con.execute(qry)
            jid = res.scalar()
            if(jid != None):
                raise Exception("该数据字段正在被使用,不能删除!")
            
            qry=select(t_qycolumns.c.ID).where(t_qycolumns.c.fcode==fcode)
            res:CursorResult=con.execute(qry)
            qid=res.scalar()
            if(qid!=None):
                raise Exception("该数据字段正在被使用,不能删除!")
            
            qry=select(t_qycondition.c.ID)
            qry=qry.where(t_qycondition.c.fcode==fcode)
            res:CursorResult=con.execute(qry)
            qcid=res.scalar()
            if(qcid!=None):
                raise Exception("该字段正在被使用，不能删除")
            
            qry = delete(t_tablecolumns).where(t_tablecolumns.c.ID==id)
            con.execute(qry)
        except Exception as es:
            raise es